﻿//  --------------------------------------------------------------------------------------
//  SimpleFeedBindingsHelpers.js
//
//  BIG HONKING NOTE:  You MUST include MiscellaneousHelpers.js and FeedSyncHelpers.js 
//                     before including this file
//  --------------------------------------------------------------------------------------

var g_SimpleFeedBindingsNamespaceURI = "http://feedsync.org/2008/namespaces/binding";

var TEXT_CONTENT_TYPE = "text";
var XML_CONTENT_TYPE = "text/xml";
var HTML_CONTENT_TYPE = "text/html";
var XHTML_CONTENT_TYPE = "application/xhtml+xml";

var NONE_TYPE = "none";
var DATETIME_TYPE = "datetime";
var BOOLEAN_TYPE = "boolean";
var NUMBER_TYPE = "number";
var FLOATINGPOINT_TYPE = "floatingpoint";

function SimpleFeedBindingCollectionClass(i_XMLDOMDocument)
    {
    var ItemContainerXPathPart;
    if (i_XMLDOMDocument.documentElement.baseName == "rss")
        ItemContainerXPathPart = "//rss/channel";
    else if (i_XMLDOMDocument.documentElement.baseName == "feed")
        ItemContainerXPathPart = "//atom:feed";

    var NamespaceDeclarations = new Array();
    NamespaceDeclarations[0] = "xmlns:sfb='" + g_SimpleFeedBindingsNamespaceURI + "'";

    var SimpleFeedBindingXmlElements = SelectNodes
        (
        i_XMLDOMDocument.documentElement,
        ItemContainerXPathPart + "/sfb:binding",
        NamespaceDeclarations,
        false
        );

    if (SimpleFeedBindingXmlElements.length == 0)
        throw "Unable to find 'sfb:binding' element!";
    
    this.m_SimpleFeedBindings = new Array();
    
    for (var Index = 0; Index < SimpleFeedBindingXmlElements.length; ++Index)
        {
        var SimpleFeedBindingXmlElement = SimpleFeedBindingXmlElements[Index];
        var SimpleFeedBinding = new SimpleFeedBindingClass(SimpleFeedBindingXmlElement);
        
        this.m_SimpleFeedBindings.push(SimpleFeedBinding);
        }
    }

function SimpleFeedBindingClass(i_SimpleFeedBindingXmlElement)
    {
    this.m_XmlElement = i_SimpleFeedBindingXmlElement;
    
    this.m_ID = this.m_XmlElement.getAttribute("id");
    this.m_Name = this.m_XmlElement.getAttribute("name");
    this.m_Title = this.m_XmlElement.getAttribute("title");
    this.m_Description = this.m_XmlElement.getAttribute("description");
    
    this.m_Namespaces = new Array();
    this.m_PickLists = new Array();
    this.m_Fields = new Array();
    
    var NamespaceDeclarations = new Array();
    NamespaceDeclarations[0] = "xmlns:sfb='" + g_SimpleFeedBindingsNamespaceURI + "'";
    
    var NamespaceXmlElements = SelectNodes
        (
        i_SimpleFeedBindingXmlElement,
        "sfb:namespace",
        NamespaceDeclarations,
        false
        );

    var NamespacesInXMLDOMDocument = GetNamespacesForXMLDOMDocument(this.m_XmlElement.ownerDocument);
         
    for (var Index = 0; Index < NamespaceXmlElements.length; ++Index)
        {
        var NamespaceXmlElement = NamespaceXmlElements[Index];
        var SimpleFeedBindingNamespace = new SimpleFeedBindingNamespaceClass(this, NamespaceXmlElement);
        
        SimpleFeedBindingNamespace.m_MappedPrefix = GetMappedXMLNamespacePrefix
            (
            NamespacesInXMLDOMDocument,
            SimpleFeedBindingNamespace.m_LocalPrefix,
            SimpleFeedBindingNamespace.m_URI
            );

        this.m_Namespaces[this.m_Namespaces.length] = SimpleFeedBindingNamespace;
        }

    var PickListXmlElements = SelectNodes
        (
        i_SimpleFeedBindingXmlElement,
        "sfb:picklist",
        NamespaceDeclarations,
        false
        );

    for (var Index = 0; Index < PickListXmlElements.length; ++Index)
        {
        var PickListXmlElement = PickListXmlElements[Index];
        var PickList = new SimpleFeedBindingPickListClass(this, PickListXmlElement);
        
        this.m_PickLists[this.m_PickLists.length] = PickList;
        }

    var FieldXmlElements = SelectNodes
        (
        i_SimpleFeedBindingXmlElement,
        "sfb:field",
        NamespaceDeclarations,
        true
        );
    
    for (var Index = 0; Index < FieldXmlElements.length; ++Index)
        {
        var FieldXmlElement = FieldXmlElements[Index];
        var Field = new SimpleFeedBindingFieldClass(this, FieldXmlElement);
        
        this.m_Fields[this.m_Fields.length] = Field;
        }
    }

function SimpleFeedBindingNamespaceClass(i_Binding, i_SFBNamespaceXmlElement)
    {
    this.m_Binding = i_Binding;
    
    this.m_XmlElement = i_SFBNamespaceXmlElement;
    
    this.m_URI = this.m_XmlElement.getAttribute("uri");
    this.m_LocalPrefix = this.m_XmlElement.getAttribute("localprefix");
    
    this.m_MappedPrefix = null;
    }
    
function SimpleFeedBindingPickListClass(i_Binding, i_SFBPickListXmlElement)
    {
    this.m_Binding = i_Binding;
    
    this.m_XmlElement = i_SFBPickListXmlElement;
    
    this.m_ID = this.m_XmlElement.getAttribute("id");

    this.m_PickListItems = new Array();

    var NamespaceDeclarations = new Array();
    NamespaceDeclarations[0] = "xmlns:sfb='" + g_SimpleFeedBindingsNamespaceURI + "'";
    
    var PickListItemXmlElements = SelectNodes
        (
        i_SFBPickListXmlElement,
        "sfb:listitem",
        NamespaceDeclarations,
        true
        );
    
    for (var Index = 0; Index < PickListItemXmlElements.length; ++Index)
        {
        var PickListItemXmlElement = PickListItemXmlElements[Index];
        var PickListItem = new SimpleFeedBindingPickListItemClass(this, PickListItemXmlElement);
        
        this.m_PickListItems[this.m_PickListItems.length] = PickListItem;
        }
    }

function SimpleFeedBindingFieldClass(i_Binding, i_SimpleFeedBindingFieldXmlElement)
    {
    this.m_Binding = i_Binding;
    
    this.m_XmlElement = i_SimpleFeedBindingFieldXmlElement;
    
    this.m_Element = this.m_XmlElement.getAttribute("element");
    this.m_PickListID = this.m_XmlElement.getAttribute("picklist");
    this.m_ContentType = this.m_XmlElement.getAttribute("contenttype");
    this.m_Type = this.m_XmlElement.getAttribute("type");
    this.m_Label = this.m_XmlElement.getAttribute("label");
    this.m_DefaultValue = this.m_XmlElement.getAttribute("defaultvalue");

    this.m_Required = GetBooleanAttributeValue(this.m_XmlElement, "required");
    this.m_Hidden = GetBooleanAttributeValue(this.m_XmlElement, "hidden");
    this.m_Array = GetBooleanAttributeValue(this.m_XmlElement, "array");
    this.m_Multiline = GetBooleanAttributeValue(this.m_XmlElement, "multiline");
    this.m_ReadOnly = GetBooleanAttributeValue(this.m_XmlElement, "readonly");    
    
    var NamespaceDeclarations = new Array();
    NamespaceDeclarations[0] = "xmlns:sfb='" + g_SimpleFeedBindingsNamespaceURI + "'";
    
    this.m_ExtensionXmlElement = SelectSingleNode
        (
        this.m_XmlElement,
        "sfb:fieldextension",
        NamespaceDeclarations,
        false
        );
    }

function SimpleFeedBindingPickListItemClass(i_PickList, i_SFBPickListItemXmlElement)
    {
    this.m_PickList = i_PickList;
    
    this.m_XmlElement = i_SFBPickListItemXmlElement;

    this.m_Value = GetTextForXMLDOMNode(this.m_XmlElement);
    this.m_Label = this.m_XmlElement.getAttribute("label");
    if (IsNullOrEmpty(this.m_Label))
        this.m_Label = this.m_Value;
    }

function SimpleFeedBindingFieldValueClass(i_SimpleFeedBindingField, i_Value)
    {
    this.m_SimpleFeedBindingField = i_SimpleFeedBindingField;
    
    if (this.m_SimpleFeedBindingField.m_Array)
        {
        if (i_Value == null)
            this.m_Values = new Array();
        else
            this.m_Values = i_Value;
        }
    else
        this.m_Value = i_Value;
    }

function GetNamespacedFieldValues(i_SimpleFeedBindingCollection, i_XMLDOMElement, i_IncludeHidden)
    {
    var SimpleFeedBinding = GetSimpleFeedBindingFromXmlElement
        (
        i_SimpleFeedBindingCollection,
        i_XMLDOMElement
        );
        
    var SimpleFeedBindingFieldValues = GetSimpleFeedBindingFieldValuesFromXmlElement
        (
        SimpleFeedBinding,
        i_XMLDOMElement, 
        i_IncludeHidden
        );

    return SimpleFeedBindingFieldValues;
    }

function GetSimpleFeedBindingFromXmlElement(i_SimpleFeedBindingCollection, i_XMLDOMElement)
    {
    var NamespaceDeclarations = new Array();
    NamespaceDeclarations[0] = "xmlns:sfb='" + g_SimpleFeedBindingsNamespaceURI + "'";

    var BindingXmlElement = SelectSingleNode
        (
        i_XMLDOMElement,
        "sfb:reference",
        NamespaceDeclarations,
        false
        );

    if (BindingXmlElement == null)
        return null;

    var ID = BindingXmlElement.getAttribute("id");
    for (var Index = 0; Index < i_SimpleFeedBindingCollection.m_SimpleFeedBindings.length; ++Index)
        {
        var Binding = i_SimpleFeedBindingCollection.m_SimpleFeedBindings[Index];
        if (Binding.m_ID == ID)
            return Binding;
        }

    return null;
    }

function GetSimpleFeedBindingFieldValuesFromXmlElement(i_SimpleFeedBinding, i_XMLDOMElement, i_IncludeHidden)
    {
    var SimpleFeedBindingFieldValues = new Object();
    
    var NamespaceDeclarations = new Array();

    for (var Index = 0; Index < i_SimpleFeedBinding.m_Namespaces.length; ++Index)
        {
        var Namespace = i_SimpleFeedBinding.m_Namespaces[Index];
        NamespaceDeclarations.push("xmlns:" + Namespace.m_MappedPrefix + "='" + Namespace.m_URI + "'");
        }

    for (var Index = 0; Index < i_SimpleFeedBinding.m_Fields.length; ++Index)
        {
        var Field = i_SimpleFeedBinding.m_Fields[Index];
        
        if ((Field.m_Hidden && !i_IncludeHidden) || Field.m_Deleted)
            continue;

        var FieldXmlElements = SelectNodes
            (
            i_XMLDOMElement,
            Field.m_Element,
            NamespaceDeclarations,
            Field.m_Required
            );
        
        if (Field.m_Array)
            {
            var Values = new Array();
            for (var Index2 = 0; Index2 < FieldXmlElements.length; ++Index2)
                {
                var FieldXmlElement = FieldXmlElements[Index2];
                Values[Values.length] = GetTextForXMLDOMNode(FieldXmlElement);
                }
                
            FieldValue = new SimpleFeedBindingFieldValueClass(Field.m_Element, Values);
            }
        else
            {
            if (FieldXmlElements.length > 1)
                throw "Non-array field with id '" + Field.m_Element + "' has multiple values!";

            var FieldXmlElement = null;
            if (FieldXmlElements.length == 1)
                FieldXmlElement = FieldXmlElements[0];

            var HasText =
                (FieldXmlElement != null) &&
                (FieldXmlElement.childNodes.length > 0) &&
                (FieldXmlElement.childNodes[0].nodeType == 3);

            var Text = "";
            if (HasText)
                {
                FieldXmlElementText = FieldXmlElement.childNodes[0];
                Text = FieldXmlElementText.text;
                }

            FieldValue = new SimpleFeedBindingFieldValueClass(Field, Text);
            }

        SimpleFeedBindingFieldValues[Field.m_Element] = FieldValue;
        }

        return SimpleFeedBindingFieldValues;
    }

function RemoveFieldValuesForXMLDOMElement(i_SimpleFeedBinding, i_XMLDOMElement, i_NamespacedFieldValues)
    {
    var NamespaceDeclarations = new Array();

    for (var Index = 0; Index < i_SimpleFeedBinding.m_Namespaces.length; ++Index)
        {
        var Namespace = i_SimpleFeedBinding.m_Namespaces[Index];
        NamespaceDeclarations.push("xmlns:" + Namespace.m_MappedPrefix + "='" + Namespace.m_URI + "'");
        }

    for (var key in i_NamespacedFieldValues)
        {
        var FieldValue = i_NamespacedFieldValues[key];
        var ExistingNodes = SelectNodes
            (
            i_XMLDOMElement,
            FieldValue.m_SimpleFeedBindingField.m_Element,
            NamespaceDeclarations
            );
        
        for (var Index = 0; Index < ExistingNodes.length; ++Index)
            {
            var ExistingNode = ExistingNodes[Index];
            ExistingNode.parentNode.removeChild(ExistingNode);
            }
        }
    }
    
function SetNamespacedFieldValuesForXmlElement(i_SimpleFeedBinding, i_XMLDOMElement, i_NamespacedFieldValues)
    {
    RemoveFieldValuesForXMLDOMElement
        (
        i_SimpleFeedBinding,
        i_XMLDOMElement,
        i_NamespacedFieldValues
        );

    var NamespaceDeclarations = new Array();
    for (var Index = 0; Index < i_SimpleFeedBinding.m_Namespaces.length; ++Index)
        {
        var Namespace = i_SimpleFeedBinding.m_Namespaces[Index];
        NamespaceDeclarations.push("xmlns:" + Namespace.m_MappedPrefix + "='" + Namespace.m_URI + "'");
        }

    for (var key in i_NamespacedFieldValues)
        {
        var FieldValue = i_NamespacedFieldValues[key];
        var ElementNames = key.split("/'");
        var NamespacePrefixes = new Array(ElementNames.length);
        var NamespaceURIs = new Array(ElementNames.length);
        
        for (var Index = 0; Index < ElementNames.length; ++Index)
            {
            var ElementName = ElementNames[Index];
            if (ElementName.indexOf(":") != -1)
                {
                var NamespacePrefix = ElementName.substring(0, ElementName.indexOf(":"));
                var Namespace = GetNamespaceFromSimpleFeedBinding(i_SimpleFeedBinding, NamespacePrefix);
                
                ElementName = ElementName.substring(ElementName.indexOf(":") + 1);
                NamespacePrefixes[Index] = Namespace.m_MappedPrefix;
                NamespaceURIs[Index] = Namespace.m_URI;
                }
                
            ElementNames[Index] = ElementName;
            }

        if (FieldValue.m_SimpleFeedBindingField.m_Array)
            {
            for (var Index2 = 0; Index2 < FieldValue.m_Values.length; ++Index2)
                {
                var Value = FieldValue.m_Values[Index2];
                
                var FieldValueXMLDOMElement = CreateXMLDOMElementHierarchy
                    (
                    i_XMLDOMElement.ownerDocument,
                    i_XMLDOMElement,
                    ElementNames,
                    NamespaceURIs,
                    NamespacePrefixes,
                    NamespaceDeclarations,
                    true
                    );           
                    
                SetTextForXMLDOMNode(FieldValueXMLDOMElement, Value);
                }
            }
        else
            {
                var FieldValueXMLDOMElement = CreateXMLDOMElementHierarchy
                    (
                    i_XMLDOMElement.ownerDocument,
                    i_XMLDOMElement,
                    ElementNames,
                    NamespaceURIs,
                    NamespacePrefixes,
                    NamespaceDeclarations
                    );           
                    
                SetTextForXMLDOMNode(FieldValueXMLDOMElement, FieldValue.m_Value);
            }
        }

    var TitleValue = ResolveExpressions(i_SimpleFeedBinding.m_Title, i_NamespacedFieldValues);
    var DescriptionValue = ResolveExpressions(i_SimpleFeedBinding.m_Description, i_NamespacedFieldValues);
    
    if (!IsNullOrEmpty(TitleValue))
        {
        var TitleXMLDOMElement = GetXMLDOMElement
            (
            i_XMLDOMElement,
            "title",
            NamespaceDeclarations,
            true
            );
            
        SetTextForXMLDOMNode(TitleXMLDOMElement, TitleValue);
        }
                
    if (!IsNullOrEmpty(DescriptionValue))
        {
        var DescriptionXMLDOMElement = GetXMLDOMElement
            (
            i_XMLDOMElement,
            "description",
            NamespaceDeclarations,
            true
            );
            
        SetTextForXMLDOMNode(DescriptionXMLDOMElement, DescriptionValue);
        }
    }
    
function GetNamespaceFromSimpleFeedBinding(i_SimpleFeedBinding, NamespacePrefix)
    {
    for (var Index = 0; Index < i_SimpleFeedBinding.m_Namespaces.length; ++Index)
        {
        var Namespace = i_SimpleFeedBinding.m_Namespaces[Index];
        if (Namespace.m_LocalPrefix == NamespacePrefix)
            return Namespace;
        }
        
    return null;
    }
    
function ResolveExpressions(i_ExpressionString, i_NamespacedFieldValues)
    {
    if (IsNullOrEmpty(i_ExpressionString))
        return "";
        
    var ExpressionElements = new Array();
    var LeftExpressionParts = i_ExpressionString.split("{");
    for (var Index = 0; Index < LeftExpressionParts.length; ++Index)
        {
        var LeftExpressionPart = LeftExpressionParts[Index];
        if (IsNullOrEmpty(LeftExpressionPart))
            continue;
            
        var RightParenthesisIndex = LeftExpressionPart.lastIndexOf("}");
        if (RightParenthesisIndex == -1)
            continue;
            
        var ExpressionElement = LeftExpressionPart.substring(0, RightParenthesisIndex);
        ExpressionElements.push(ExpressionElement);
        }

    var ResolvedExpression = i_ExpressionString;
    for (var Index = 0; Index < ExpressionElements.length; ++Index)
        {
        var ExpressionElement = ExpressionElements[Index];
        ResolvedExpression = ResolvedExpression.replace ("{" + ExpressionElement + "}", i_NamespacedFieldValues[ExpressionElement].m_Value);
        }        
        
    return ResolvedExpression;
    }
